using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;

class ZoomBlurPass : ScriptableRenderPass
{
    private static readonly string k_RenderTag = "Render ZoomBlur Effects";

    private static readonly int MainTexID = Shader.PropertyToID("_MainTex");
    private static readonly int TempTargetID = Shader.PropertyToID("_TempTargetZoomBlur");
    private static readonly int FocusPowerID = Shader.PropertyToID("_FocusPower");
    private static readonly int FocusDetailID = Shader.PropertyToID("_FocusDetail");
    private static readonly int FocusScreenPositionID = Shader.PropertyToID("_FocusScreenPosition");
    private static readonly int ReferenceResolutionXID = Shader.PropertyToID("_ReferenceResolutionX");

    private ZoomBlur m_zoomBlur;
    private Material m_zoomBlurMat;
    private ScriptableRenderer m_renderer;
    
    public ZoomBlurPass(RenderPassEvent evt)
    {
        renderPassEvent = evt;
        var shader = Shader.Find("Samples/ZoomBlur");
        if (null == shader)
        {
            Debug.LogError("Shader not found.");
            return;
        }
        m_zoomBlurMat = CoreUtils.CreateEngineMaterial(shader);
    }

    public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
    {
        // 环境准备
        if (null == m_zoomBlurMat)
        {
            Debug.LogError("Material not found.");
            return;
        }

        if (false == renderingData.cameraData.postProcessEnabled) return;
        
        // 获取VolumeComponent
        var stack = VolumeManager.instance.stack;
        m_zoomBlur = stack.GetComponent<ZoomBlur>();
        if (null == m_zoomBlur) return;
        if (false == m_zoomBlur.IsActive()) return;

        // 获取命令缓存
        var cmd = CommandBufferPool.Get(k_RenderTag);
        Render(cmd, ref renderingData);
        
        // 回收命令缓存
        context.ExecuteCommandBuffer(cmd);
        CommandBufferPool.Release(cmd);
    }

    public void Setup(in ScriptableRenderer renderer)
    {
        m_renderer = renderer;
    }

    private void Render(CommandBuffer cmd, ref RenderingData renderingData)
    {
        ref var cameraData = ref renderingData.cameraData;
        var source = m_renderer.cameraColorTargetHandle;
        var destination = TempTargetID;

        var w = cameraData.camera.scaledPixelWidth;
        var h = cameraData.camera.scaledPixelHeight;
        
        // 设置材质参数
        m_zoomBlurMat.SetFloat(FocusPowerID, m_zoomBlur.focusPower.value);
        m_zoomBlurMat.SetInt(FocusDetailID, m_zoomBlur.focusDetail.value);
        m_zoomBlurMat.SetVector(FocusScreenPositionID, m_zoomBlur.focusScreenPosition.value);
        m_zoomBlurMat.SetFloat(ReferenceResolutionXID, m_zoomBlur.referenceResolutionX.value);
        
        // shader的第一个pass
        int shaderPass = 0;
        
        cmd.SetGlobalTexture(MainTexID, source);
        // 在清理RenderTarget前，如果存在后处理堆栈就需要申请一张临时的render texture，
        // 我们使用camera buffer的CommandBuffer.GetTemporaryRT方法来申请这样一张Texture
        // 传入着色器属性ID以及与相机像素尺寸相匹配的纹理宽高、FilterMode、RenderTextureFormat
        cmd.GetTemporaryRT(destination, w, h, 0, FilterMode.Point, RenderTextureFormat.Default);
        cmd.Blit(source, destination);
        cmd.Blit(destination, source, m_zoomBlurMat, shaderPass);
    }
}
